package applet;

import java.applet.Applet;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutput;
import java.io.ObjectOutputStream;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.SocketAddress;
import java.net.SocketException;
import java.net.UnknownHostException;
import java.util.HashMap;

import netscape.javascript.JSObject;
import server.ServerPacket;

public class ServerConnector extends Applet{

	/**
	 * 
	 */
	private static final long serialVersionUID = -3870131775694279754L;

	private static final int SERVER_SOCKET = 12345;//remote server
	
	private static final String SERVER = "macs.citadel.edu";//could be localhost for testing
	
	DatagramSocket dsock;
	
	InetSocketAddress server_socket;
	
	public void init() {
		System.out.println("constructor accessed");
		try {
			dsock = new DatagramSocket();
			
//			this.server_socket = new InetSocketAddress(
//								InetAddress.getByName(SERVER),
//								SERVER_SOCKET);
			this.server_socket = 
					new InetSocketAddress(	InetAddress.getLocalHost(),//change this
											SERVER_SOCKET);
			System.out.println("\nServer address is:" + server_socket.getHostString() + "\n");
		} catch (SocketException | UnknownHostException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
			
	}
	
	public Boolean register(String user_id, String password) {
		//form registration packet
		ServerPacket pkt = 
				new ServerPacket(ServerPacket.RequestType.Register, 
									user_id, password);
		
		//send to server
		byte[] temp = this.serialize(pkt);
		try {
			DatagramPacket dp = 
						new DatagramPacket(temp, temp.length, server_socket);
			dsock.send(dp);
			
			//wait for timeout and return
			dsock.setSoTimeout(1000);
			dsock.receive(dp);
			//??
			
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
			return false;
		}
		return true;
	}
	
	public Boolean login(String user_id, String password) {
		//form registration packet
		JSObject window = JSObject.getWindow(this);
		window.setMember("debug_msg", "Calling Login!!!");
		window.eval("debugMsg()");
				ServerPacket pkt = 
						new ServerPacket(ServerPacket.RequestType.Login, 
											user_id, password);
				
				//send to server
				byte[] temp = this.serialize(pkt);
				try {
					DatagramPacket dp = 
								new DatagramPacket(temp, temp.length, server_socket);
					dsock.send(dp);
					
					//wait for timeout and return
					dsock.setSoTimeout(1000);
					dsock.receive(dp);
					//??
					
				} catch (IOException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
					return false;
				}
				return true;
		
	}
	
	public HashMap<String, InetSocketAddress> getUsers(String user_id) {
		//form registration packet
				ServerPacket pkt = 
						new ServerPacket(ServerPacket.RequestType.GetUsers, 
											user_id);
				
				//send to server
				byte[] temp = this.serialize(pkt);
				HashMap<String, InetSocketAddress> map = null;
				try {
					DatagramPacket dp = 
								new DatagramPacket(temp, temp.length, server_socket);
					dsock.send(dp);
					
					//wait for timeout and return
					dsock.setSoTimeout(1000);
					dsock.receive(dp);
					
					//extract data and add to map
					map = new HashMap<String, InetSocketAddress>();
					
					pkt = this.deserialize(dp.getData());
					
					byte[][] user_data = pkt.getUserData();
					
					InetSocketAddress[] address_list = pkt.getAddr();
					
					for(int i = 0; i < user_data.length; i++) {
						map.put(new String(user_data[i]), address_list[i]);
					}
					
				} catch (IOException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
				return map;
		
	}
	
	public Boolean disconnect(String user_id) {
		//form registration packet
				ServerPacket pkt = 
						new ServerPacket(ServerPacket.RequestType.Disconnect, 
											user_id);
				
				//send to server
				byte[] temp = this.serialize(pkt);
				try {
					DatagramPacket dp = 
								new DatagramPacket(temp, temp.length, server_socket);
					dsock.send(dp);
					
					//wait for timeout and return
					dsock.setSoTimeout(1000);
					dsock.receive(dp);
					//??
					
				} catch (IOException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
					return false;
				}
				return true;
				
	}
	
	private byte[] serialize(ServerPacket response) {
		ByteArrayOutputStream bos = new ByteArrayOutputStream();
		ObjectOutput out = null;
		byte[] temp = null;
		try {
		  out = new ObjectOutputStream(bos);   
		  out.writeObject(response);
		  temp = bos.toByteArray();
		  System.out.println("Size of ServerPacket in bytes: " + temp.length + "\n");
		  
		} catch (IOException e) {
			e.printStackTrace();
		}  finally {
		
		  try {
		    if (out != null) {
		      out.close();
		    }
		  } catch (IOException ex) {
		    // ignore close exception
		  }
		  try {
		    bos.close();
		  } catch (IOException ex) {
		    // ignore close exception
		  }
		}
		
		return temp;
	}

	private ServerPacket deserialize(byte[] bs) {
		 ObjectInputStream ob_in;
			try {
				ob_in = new ObjectInputStream(new ByteArrayInputStream(bs));
		        ServerPacket obj = (ServerPacket) ob_in.readObject();
		        ob_in.close();
		        return obj;
			} catch (IOException | ClassNotFoundException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		
		return null;
	}
}
